/*
 * Copyright (c) 2025 Huawei Device, Inc. Ltd. and <马弓手>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "rawfile_request.h"
#include "CordovaViewController.h"
#include "HttpCode.h"
#include "hilog/log.h"
#include "MemPool.h"
#include "rawfile/raw_file.h"
#include "rawfile/raw_file_manager.h"
#include "Application.h"
#include "connpool.h"
#include "fileCache.h"
#include "file/FileUtils.h"
#include "HttpUrl.h"
#include "SystemCookieManager.h"
#include <cstddef>
#include <map>
#include <sys/stat.h>
#include <network/netmanager/net_connection.h>
#include <network/netmanager/net_connection_type.h>

#undef LOG_TAG
#define LOG_TAG "ss-handler"

namespace {
// HttpBodyStream的读回调。
void ReadCallback(const ArkWeb_HttpBodyStream  *httpBodyStream, uint8_t* buffer, int bytesRead)
{
    OH_LOG_INFO(LOG_APP, "read http body back.");
    RawfileRequest *rawfileRequest = (RawfileRequest *)OH_ArkWebHttpBodyStream_GetUserData(httpBodyStream);
    if(bytesRead > 0) {
        rawfileRequest->m_vecRequestHttpBody.insert(rawfileRequest->m_vecRequestHttpBody.end(), buffer, buffer+bytesRead);
    }
    bool isEof = OH_ArkWebHttpBodyStream_IsEof(httpBodyStream);
    if (!isEof) {
        memset(buffer, 0, ((CMemPool*)Application::g_memPool)->GetPageSize());
        OH_ArkWebHttpBodyStream_Read(httpBodyStream, buffer, ((CMemPool*)Application::g_memPool)->GetPageSize());
    } else {
        ((CMemPool*)Application::g_memPool)->FreePage((char*)buffer);
        if (rawfileRequest) {
            if(!((CHttpGroupRunner*)Application::g_httpGroupRunner)->AddTask(rawfileRequest)) {
                OH_LOG_ERROR(LOG_APP, "Thread reaches boundary, adding task failed");
                rawfileRequest->Response4XX(HttpCode::FORBIDDEN);
            }
        }
    }
}


// ArkWeb_HttpBodyStream的初始化回调。
void InitCallback(const ArkWeb_HttpBodyStream *httpBodyStream, ArkWeb_NetError result)
{
    OH_LOG_INFO(LOG_APP, "init http body stream done %{public}d.", result);
    bool isChunked = OH_ArkWebHttpBodyStream_IsChunked(httpBodyStream);
    OH_LOG_INFO(LOG_APP, "http body stream is chunked %{public}d.", isChunked);
    
    vector<SMemPage> vecMemPage;
    ((CMemPool*)Application::g_memPool)->MallocPage(vecMemPage, 1);
    if(vecMemPage.size() < 1) {
        OH_LOG_ERROR(LOG_APP, "((CMemPool*)Application::g_memPool)->MallocPage(vecMemPage, 1) == NULL");
        return;
    }
    unsigned  char* buffer = (unsigned  char*)vecMemPage[0].m_point;
    memset(buffer, 0, ((CMemPool*)Application::g_memPool)->GetPageSize());
    OH_ArkWebHttpBodyStream_Read(httpBodyStream, buffer, ((CMemPool*)Application::g_memPool)->GetPageSize());
}
}  // namespace


RawfileRequest::RawfileRequest(const ArkWeb_ResourceRequest *resourceRequest,
                               const ArkWeb_ResourceHandler *resourceHandler,
                               const NativeResourceManager* resourceManager,
                               const ArkWeb_SchemeHandler *schemeHandler,
                               const string & strSchemeDomainPort)
        : m_resourceRequest(resourceRequest),
          m_resourceHandler(resourceHandler),
          m_resourceManager(resourceManager),
          m_schemeHandler(schemeHandler),
          m_strSchemeDomainPort(strSchemeDomainPort),
          m_response(NULL) 
{
    OH_ArkWeb_CreateResponse(&m_response);
}

RawfileRequest::~RawfileRequest() {}

void RawfileRequest::Start()
{
    OH_LOG_INFO(LOG_APP, "start a webview request.");
    if(Application::g_strTmpUrl == "" || !Application::isValidSchemeHandler(m_schemeHandler)) {
        return;
    }
    
    OH_ArkWebResourceRequest_GetHttpBodyStream(m_resourceRequest, &m_stream);
    if (m_stream) {
        OH_LOG_INFO(LOG_APP, "have http body stream");
        OH_ArkWebHttpBodyStream_SetUserData(m_stream, this);
        OH_ArkWebHttpBodyStream_SetReadCallback(m_stream, ReadCallback);
        OH_ArkWebHttpBodyStream_Init(m_stream, InitCallback);
    } else {
        if(!((CHttpGroupRunner*)Application::g_httpGroupRunner)->AddTask(this)) {
            OH_LOG_ERROR(LOG_APP, "Thread reaches boundary, adding task failed");
            Response4XX(HttpCode::FORBIDDEN);
        }
    }
}

/*
*此函数主要完成四个功能，此函数不上全局锁，已提高效率，另外此函数在可变线程池中运行
*1，加载rawfile文件，通常情况下本地的网页放在此目录下
*2，加载沙箱路径的本地文件，域名为localhost或者scheme为cdvfile
*3，加载在线资源，例如js，css、img和font等
*4，发送动态请求数据
*/
void RawfileRequest::ReadRawfileDataOnWorkerThread(void* pMaxBuffer, const int nBufSize, const int nCountOfTask)
{
    OH_LOG_INFO(LOG_APP, "Processing task... %{public}d", nCountOfTask);
    //前端webview已经destroy，不再发送请求
    if(Application::g_strTmpUrl == "" || !Application::isValidSchemeHandler(m_schemeHandler) || pMaxBuffer == nullptr) {
        Response4XX(HttpCode::BAD_REQUEST);
        return;
    }
    
    //1，解析url
    char* url = nullptr;
    if(!WebResourceRequest_GetUrl(&url)) {
        Response4XX(HttpCode::BAD_REQUEST);
        return;
    }
    string urlPath = url;
    urlPath = Application::getResourceObj(m_schemeHandler, urlPath);
    string requestAddress = "";
    OH_ArkWeb_ReleaseString(url);
    urlPath = urlPath.erase(0, urlPath.find_first_not_of(" "));
    urlPath = urlPath.erase(urlPath.find_last_not_of(" ") + 1);
    if(urlPath.find("//") != string::npos) {
        requestAddress = urlPath.substr(urlPath.find("//")+2);
    }
    if(urlPath.find(Application::g_strTmpUrl) != string::npos) {
        std::size_t position = urlPath.find(Application::g_strTmpUrl)+Application::g_strTmpUrl.length();
        if (position != std::string::npos) {
            m_rawfilePath = urlPath.substr(position + 1);
            int afterPos = m_rawfilePath.find("#");
            if(afterPos != string::npos) {
                m_rawfilePath = m_rawfilePath.substr(0, afterPos);
            }
            afterPos = m_rawfilePath.find("?");
            if(afterPos != string::npos) {
                m_rawfilePath = m_rawfilePath.substr(0, afterPos);
            }
        }
    }
    
    //2,解析http/https协议类型
    int nPort = 0;
    bool isHttps = false;
    bool isFile = false;
    if(urlPath.find("https") == 0 ) {
        isHttps = true;
        nPort = 443;
    } else if(urlPath.find("http") == 0) {
        isHttps = false;
        nPort = 80;
    } else if(urlPath.find("cdvfile") == 0 ){
       isFile = true;
    } else {
        Response4XX(HttpCode::BAD_REQUEST);
        return;
    }
    
    //3解析域名修改请求地址
    string strDomainAndPort;
    string strDomain;
    if(isFile == false && urlPath.find("//") != string::npos) {
        strDomain = urlPath.substr(urlPath.find("//")+2);
        strDomainAndPort = strDomain;
        if(strDomain.find("/") != string::npos) {
            strDomain = strDomain.substr(0, strDomain.find("/"));
            strDomainAndPort = strDomain;
        }
        if(strDomain.find(":") != string::npos) {
            string strPort = strDomain.substr(strDomain.find(":")+1);
            strDomain = strDomain.substr(0, strDomain.find(":"));
            nPort = atoi(strPort.c_str());
        }    
        requestAddress = requestAddress.substr(strDomainAndPort.length());
    }
    
    string strCachePath = Application::g_strCachePath;
    if(strDomain == "localhost") {//访问本地文件
       strCachePath = "";
       string strBaseDir = Application::g_databaseDir.substr(0, Application::g_databaseDir.find("el2/database")-1);
        if(requestAddress.find(strBaseDir) != 0) {//cdv格式的文件
            requestAddress = FileUtils::getNativeUrl(strDomain+requestAddress);
        }
        if(requestAddress.find("?") != string::npos) {//源文件路径
            requestAddress = requestAddress.substr(0, requestAddress.find("?"));
        }
    }
    
    if(isFile) {//访问本地文件
        strCachePath = "";
        if(requestAddress.find("/") != 0) {
            requestAddress = "/" + requestAddress;
        }
        requestAddress = FileUtils::getNativeUrl(requestAddress);
        if(requestAddress.find("?") != string::npos) {
            requestAddress = requestAddress.substr(0, requestAddress.find("?"));
        }
    }
    
    //4,解析method
    char* method = nullptr;
    if(!WebResourceRequest_GetMethod(&method)) {
        Response4XX(HttpCode::BAD_REQUEST);
        return;
    }
    string strMethod = method;
    OH_ArkWeb_ReleaseString(method);
    
    
    //5,解析请求类型
    int32_t resourceType = -1;
    if(!WebResourceRequest_GetResourceType(resourceType) || resourceType == -1) {
        Response4XX(HttpCode::BAD_REQUEST);
        return;
    }
    
    //6,解析header
    map<string, string> mapHeader;
    ArkWeb_RequestHeaderList* headerList = NULL;
    if(!WebResourceRequest_GetRequestHeaders(&headerList) || headerList == NULL) {
        Response4XX(HttpCode::BAD_REQUEST);
        return;
    }
    int headerListSize = OH_ArkWebRequestHeaderList_GetSize(headerList);
    for(int i=0; i<headerListSize; i++) {
        char* key;
        char* value;
        OH_ArkWebRequestHeaderList_GetHeader(headerList, i, &key, &value);
        mapHeader[key] = value;
        OH_ArkWeb_ReleaseString(key);
        OH_ArkWeb_ReleaseString(value);
    }
    OH_ArkWebRequestHeaderList_Destroy(headerList);
    
    //7,查找是否设置了代理
    bool isHttpProxy = false;
    NetConn_HttpProxy httpProxy;
    memset(httpProxy.host, 0 ,sizeof(httpProxy.host));
    httpProxy.port = 0;
    if(m_rawfilePath.empty() && !isFile && strDomain != "localhost" && strDomain != Application::g_strTmpUrl && OH_NetConn_GetDefaultHttpProxy(&httpProxy) == 0) {
        if(strlen(httpProxy.host) > 0 && httpProxy.port != 0) {
            isHttpProxy = true;
            isHttps = false;
        }
    }
    
    //8,判断是否设置了withCredentials，true:预检请求跨域不得返回*
    bool isAllowCredentials = Application::getIsAllowCredentials(m_schemeHandler);
    string strCustomHttpHeaders = Application::getCustomHttpHeaders(m_schemeHandler);
    string strOrigin = "https://"+Application::g_strTmpUrl;
    if(mapHeader.find("Origin") != mapHeader.end()) {
        strOrigin = mapHeader["Origin"];
    }
    OH_LOG_INFO(LOG_APP, "create m_response(%{public}p)", m_response);
    
    /*
    *9,处理预检请求
    * 拦截并代服务器处理预检请求，以便绕过所有的跨域请求
    * 由于前后分离开发，前端开发人员无法控制和配置后端
    * 通过此方法是伪装跨域请求为同源
    * withCredentials=true时，设置跨域请求
    */
     int nArkWebRetCode = 0;
    if(strMethod == "OPTIONS") {
        if((nArkWebRetCode = WebResponse_SetStatus(HttpCode::NO_CONTENT)) != ARKWEB_NET_OK) {//预检请求状态码是204
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "OH_ArkWebResponse_SetStatus(204) == %{public}d",  nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        } 
        
        if(isAllowCredentials) {
            if((nArkWebRetCode = WebResponse_SetHeaderByName( "Access-Control-Allow-Origin", strOrigin))!= ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Origin\", \"%{public}s\") == %{public}d", strOrigin.c_str(), nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "OH_ArkWebResponse_SetHeaderByName( \"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Headers", strCustomHttpHeaders)) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Headers\", \"%{public}s\") == %{public}d", strCustomHttpHeaders.c_str(), nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Credentials", "true")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Credentials\", \"true\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
        } else {
            if((nArkWebRetCode = WebResponse_SetHeaderByName( "Access-Control-Allow-Origin", "*"))!= ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Origin\", \"*\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Methods", "*")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "OH_ArkWebResponse_SetHeaderByName( \"Access-Control-Allow-Methods\", \"*\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Headers", "*")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Headers\", \"*\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Credentials", "false")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Credentials\", \"false\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
        }
        
        if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Max-Age", "86400")) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName( \"Access-Control-Max-Age\", \"86400\") == %{public}d",  nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Keep-Alive", "timeout=2, max=60")) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Keep-Alive\", \"timeout=2, max=60\") == %{public}d",  nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Connection", "Keep-Alive")) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName( \"Connection\", \"Keep-Alive\") == %{public}d",  nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        } else if((nArkWebRetCode = WebResponse_SetStatusText("OK")) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetStatusText(\"OK\") == %{public}d",  nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        } 
        DidReceiveResponse();
        DidFinish();
        return;
    }
    
    //不是获取本地文件，也不是白名单允许的
    if(!isFile && !IsAllowUrl(urlPath)) {
        Response4XX(HttpCode::FORBIDDEN);
        return;
    }
    
    //获取部分文件内容，计算开始字节和结束字节
    long lngRangeStart = 0;//部分返回开始字节
    long lngRangeEnd = 0;//部分返回结束字节
    if(mapHeader.find("Range") != mapHeader.end()) {
        string strRangeValue = mapHeader["Range"];
        OH_LOG_INFO(LOG_APP, "Range:%{public}s", strRangeValue.c_str());
        if(strRangeValue.find("bytes=") != string::npos) {
            strRangeValue = strRangeValue.substr(6);
            if(strRangeValue.find("-") != string::npos) {
                string strRangeStart = strRangeValue.substr(0, strRangeValue.find("-"));
                string strRangeEnd = strRangeValue.substr(strRangeValue.find("-")+1);
                lngRangeStart = atol(strRangeStart.c_str());
                lngRangeEnd = atol(strRangeEnd.c_str());
            }
        }
    }
    
    /*
    *10，发送请求获取资源
    *加载本地资源：
    *   域名为localhost从本地沙箱路径加载文件
    *   scheme是cdvfile从本地沙箱路径加载文件
    *其他为从服务器获取资源，如果服务器资源本地已经缓存，且缓存未过期，从本地缓存加载文件，不发送请求
    */
    string strHttpUrl = isHttps?"https://"+strDomainAndPort:"http://"+strDomainAndPort;
    if((m_rawfilePath.empty() && (resourceType == MAIN_FRAME || resourceType == SUB_FRAME || resourceType == STYLE_SHEET || resourceType == SCRIPT || resourceType == IMAGE || resourceType == FONT_RESOURCE || resourceType == FAVICON)) || strDomain == "localhost" || isFile) {
        /*
        *strRequestFileName为本地缓存的文件
        *沙箱路径文件，缓存时间不限制
        *网络加载的文件缓存时间默认24小时，自定义缓存时间在config.xml里面配置cordova-cache-duration参数，见文档说明
        */
        string strRequestFileName =  "";
        if(isFile || strDomain == "localhost") {
            strRequestFileName = requestAddress;//本地沙箱路径文件名
        }else {
            strRequestFileName = "/"+HttpUrl::generateMD5(urlPath);//网络请求本地缓存文件名,文件名为请求url的md5值
        }
        
        //在获取在线资源时，http请求body有内容，清除本地缓存，从服务器加载
        if(!isFile && strDomain != "localhost" && m_vecRequestHttpBody.size() > 0 && FileCache::IsFile(strRequestFileName, strCachePath)) {
            FileCache::deleteFile(strCachePath+strRequestFileName);
        }
        
        //判断在线资源本地缓存是否已超期
        if(!isFile && strDomain != "localhost" && FileCache::IsFile(strRequestFileName, strCachePath)) {
            struct stat file_stat;
            string strFile = strCachePath + strRequestFileName;
            if (stat(strFile.c_str(), &file_stat) == 0) {
                time_t file_mtime = file_stat.st_mtime;
                time_t current_time;
                time(&current_time);
                double dbDiffSeconds = difftime(current_time, file_mtime);
                if(dbDiffSeconds > ((CordovaViewController*)Application::g_cordovaViewController)->getCordovaCacheDuration()) {
                    FileCache::deleteFile(strCachePath+strRequestFileName);
                }
            }
        }
        
        //部分返回文件不全，删除文件缓存
        if(!isFile && strDomain != "localhost" && mapHeader.find("Range") != mapHeader.end() && FileCache::IsFile(strRequestFileName, strCachePath)) {
             FileCache::deleteFile(strCachePath+strRequestFileName);
        }
        
        //开始代理发送请求,如果域名是localhost后续在第14步从本地沙箱路径加载文件
        map<string, string>  mapRespHeaders;
        if(!strDomain.empty() && strDomain != "localhost" && !FileCache::IsFile(strRequestFileName, strCachePath)) {
            string strRequest;
            strRequest = strMethod + " " + requestAddress + " HTTP/1.1\r\n";//%s %s HTTP/1.1\r\n
            
            /*
            *从分页式内存管理的中申请一页内存，用于设置http头，一页内存最小1M，
            *现代浏览器http头不会超过1M大小，因此内存不会溢出
            *使用内存池内存，不用频繁的申请和释放内存，系统更稳定，使用完后注意将此页内存放回池中，避免泄漏
            */
            vector<SMemPage> vecMemBuf;
            ((CMemPool*)Application::g_memPool)->MallocPage(vecMemBuf, 1);
            if(vecMemBuf.size() < 1) {
                OH_LOG_ERROR(LOG_APP, "((CMemPool*)Application::g_memPool)->MallocPage(vecMemBuf, 1) == NULL");
                return;
            }
            
            char* szBuf = vecMemBuf[0].m_point;
            if(nPort == 80 || nPort == 443)
                sprintf(szBuf, "Host:%s\r\n", strDomain.c_str());
            else
                sprintf(szBuf, "Host:%s:%d\r\n", strDomain.c_str(), nPort);
            strRequest += szBuf;
            
            //设置http头，同时剔除跨域http头
            //剔除Sec-Fetch-*头，如果您的服务器部署了基于Fetch Metadata的安全策略，请求会被拒绝，后续版本迭代中会像浏览器一样增加Sec-Fetch-*头
            string strCookie;
            for(map<string,string>::iterator iter = mapHeader.begin(); iter != mapHeader.end(); ++iter){
                if(iter->first == "Origin" || iter->first == "Sec-Fetch-Dest" || iter->first == "Sec-Fetch-Mode" || iter->first == "Sec-Fetch-Site"|| iter->first == "If-Modified-Since"|| iter->first == "If-None-Match") {
                    continue;
                }
                if(strcasecmp(iter->first.c_str(),"cookie") == 0) {
                    strCookie = iter->second;
                    continue;
                }
                sprintf(szBuf, "%s:%s\r\n", iter->first.c_str(),iter->second.c_str());
                strRequest += szBuf;
            }
            
            strCookie = SystemCookieManager::getCookie(strHttpUrl, strCookie);
            if(!strCookie.empty()) {
                strRequest += "Cookie:";
                strRequest += strCookie;
                strRequest += "\r\n";
            }
            
            sprintf(szBuf, "Connection:Keep-Alive\r\n");
            strRequest += szBuf;
            
            if(m_vecRequestHttpBody.size() > 0) {
                sprintf(szBuf, "Keep-Alive:timeout=5, max=1000\r\n");
                strRequest += szBuf;
                sprintf(szBuf, "Content-Length:%lu\r\n\r\n", m_vecRequestHttpBody.size());
                strRequest += szBuf;
                strRequest.insert(strRequest.length(), (const char*)&m_vecRequestHttpBody[0], m_vecRequestHttpBody.size());
            } else {
                sprintf(szBuf, "Keep-Alive:timeout=5, max=1000\r\n\r\n");
                strRequest += szBuf;
            }
            ((CMemPool*)Application::g_memPool)->FreePage(vecMemBuf);
            
            //如果webview设置了代理，使用代理地址转发保持和webview一致
            if(isHttpProxy) {
                strDomain = httpProxy.host;
                nPort = httpProxy.port;
            }
            
            ConnPoolManage* connPoolManage = (ConnPoolManage*)Application::g_connPoolManage;
            ConnPool* pool = connPoolManage->getConnPool(strDomain);
            if(pool == NULL) {
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
            
            //开始实际发送请求
            memset(pMaxBuffer,0, nBufSize);
            if(isHttps) {
                bool isClose = false;
                SSL* ssl = NULL;
                if(!pool->getSSL(&ssl, nPort)) {
                    OH_LOG_ERROR(LOG_APP, "pool->getSocket(&ssl) == false");
                }else if(!pool->sendWithTimeOut(ssl, strRequest, std::ref(m_stopped))) {
                    OH_LOG_ERROR(LOG_APP, "pool->sendWithTimeOut(ssl, strRequest) == false");
                }else if(!pool->recvHttpWithTimeOut(ssl, strRequestFileName, mapRespHeaders, strCachePath, pMaxBuffer, nBufSize, isClose, std::ref(m_stopped))) {
                    OH_LOG_ERROR(LOG_APP, "pool->recvHttpWithTimeOut(ssl, strRequestFileName, mapRespHeaders, pMaxBuffer, nBufSize, isReconnect) == false");
                }
                pool->freeSocket(ssl, true);
            } else {
                bool isClose = false;
                int nSocket = -1;
                if(!pool->getSocket(nSocket, nPort)) {
                    OH_LOG_ERROR(LOG_APP, "pool->getSocket(nSocket) == false");
                }else if(!pool->sendWithTimeOut(nSocket, strRequest, std::ref(m_stopped))) {
                    OH_LOG_ERROR(LOG_APP, "pool->sendWithTimeOut(nSocket, strRequest) == false");
                }else if(!pool->recvHttpWithTimeOut(nSocket, strRequestFileName, mapRespHeaders, strCachePath, pMaxBuffer, nBufSize, isClose, std::ref(m_stopped))) {
                    OH_LOG_ERROR(LOG_APP, "pool->recvHttpWithTimeOut(nSocket, strRequestFileName, pMaxBuffer, nBufSize, isReconnect) == false");
                }
                pool->freeSocket(nSocket, true);
            }
            
            if(m_stopped) {
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
            
            int httpCode = pool->getHttpCode((char*)pMaxBuffer, strlen((char*)pMaxBuffer));
            //重定向返回，webview会自动重新发起新的请求
            if(HttpCode::isRedirection(httpCode)) {
                if((nArkWebRetCode = WebResponse_SetStatus( httpCode)) != ARKWEB_NET_OK) {
                    if(nArkWebRetCode) {
                        OH_LOG_ERROR(LOG_APP, "WebResponse_SetStatus(httpCode{%{public}d}) == %{public}d", httpCode, nArkWebRetCode);
                    }
                    Response4XX(HttpCode::BAD_REQUEST);
                    return;
                }
                for(map<string,string>::iterator iter = mapRespHeaders.begin(); iter != mapRespHeaders.end(); ++iter){
                    if((nArkWebRetCode = WebResponse_SetHeaderByName(iter->first, iter->second)) != ARKWEB_NET_OK) {
                        if(nArkWebRetCode) {
                            OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(iter->first.c_str(){%{public}s}, iter->second.c_str(){%{public}s})) == %{public}d", iter->first.c_str(), iter->second.c_str(), nArkWebRetCode);
                        }
                        Response4XX(HttpCode::BAD_REQUEST);
                        return;
                    }
                }
                DidReceiveResponse();
                DidFinish();
                return;  
            }
            
            //请求资源只有状态码200才会有正确的资源数据返回
            if(httpCode != HttpCode::OK) {
                Response4XX(httpCode);
                return;
            }
        }
        
        //服务端请求成功后，缓存到本地文件，或者直接就是本地文件
        if(!FileCache::IsFile(strRequestFileName, strCachePath)) {
            Response4XX(HttpCode::NOT_FOUND);
            return;
        }
        
        //设置httpcode
        if((nArkWebRetCode = WebResponse_SetStatus(HttpCode::OK)) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetStatus(HttpCode::OK{200}) == %{public}d", nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        
        //设置mime
        string strMimeType = HttpUrl::GetMimeType(resourceType, urlPath);
        if((nArkWebRetCode = WebResponse_SetMimeType(strMimeType)) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetMimeType(strMimeType{%{public}s}) == %{public}d",strMimeType.c_str(), nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        
        //自定义设置http头的相关跨域头，绕过webview的跨域拦截
        if(isAllowCredentials) {
            if((nArkWebRetCode = WebResponse_SetHeaderByName( "Access-Control-Allow-Origin", strOrigin))!= ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Origin\", \"%{public}s\") == %{public}d", strOrigin.c_str(), nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "OH_ArkWebResponse_SetHeaderByName( \"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Headers", strCustomHttpHeaders)) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Headers\", \"%{public}s\") == %{public}d", strCustomHttpHeaders.c_str(), nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Credentials", "true")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Credentials\", \"true\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
        } else {
            if((nArkWebRetCode = WebResponse_SetHeaderByName( "Access-Control-Allow-Origin", "*")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Origin\", \"*\") == %{public}d", nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Methods", "*")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "OH_ArkWebResponse_SetHeaderByName(\"Access-Control-Allow-Methods\", \"*\") == %{public}d", nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Headers", "*")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Headers\", \"*\") == %{public}d", nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Credentials", "false")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Credentials\", \"false\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
        }
        //这里注释编码，如果服务端返回的非utf8字符，设置编码会导致webview乱码，不设置编码由webview根据返回的http头自行处理
        //OH_ArkWebResponse_SetCharset(m_response, "UTF-8");
        
        /*
        *自定义设置response的http头
        *自定义处理服务器返回的Set-Cookie头
        */
        for(map<string,string>::iterator iter = mapRespHeaders.begin(); iter != mapRespHeaders.end(); ++iter){
            if(strcasecmp(iter->first.c_str(), "Access-Control-Allow-Origin") != 0 
                && strcasecmp(iter->first.c_str(), "Access-Control-Allow-Methods") != 0 
                && strcasecmp(iter->first.c_str(), "Access-Control-Allow-Headers") != 0 
                && strcasecmp(iter->first.c_str(), "Access-Control-Allow-Credentials") != 0 
                && strcasecmp(iter->first.c_str(), "Transfer-Encoding") != 0 
                && strcasecmp(iter->first.c_str(), "Content-Encoding") != 0 
                && strcasecmp(iter->first.c_str(), "Content-Length") != 0 
                && strcasecmp(iter->first.c_str(),"Content-Type") != 0) {
                if((nArkWebRetCode = WebResponse_SetHeaderByName(iter->first, iter->second)) != ARKWEB_NET_OK) {
                    if(nArkWebRetCode) {
                        OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(iter->first.c_str(){%{public}s}, iter->second.c_str(){%{public}s}) == %{public}d",iter->first.c_str(),iter->second.c_str(), nArkWebRetCode);
                    }
                    Response4XX(HttpCode::BAD_REQUEST);
                    return;
                }
            }
            
            if(strcasecmp(iter->first.c_str(), "Content-Type") == 0) {
                string strMimeType = iter->second;
                string strCharset = "";
                if(strMimeType.find(";") != string::npos) {
                    strCharset = strMimeType.substr(strMimeType.find(";")+1);
                    strMimeType = strMimeType.substr(0, strMimeType.find(";"));
                }
                if((nArkWebRetCode = WebResponse_SetMimeType(strMimeType)) != ARKWEB_NET_OK) {
                    if(nArkWebRetCode) {
                        OH_LOG_ERROR(LOG_APP, "WebResponse_SetMimeType(strMimeType.c_str(){%{public}s})== %{public}d",strMimeType.c_str(), nArkWebRetCode);
                    }
                    Response4XX(HttpCode::BAD_REQUEST);
                    return;
                }
                if(strCharset.find("charset=") != string::npos) {
                    strCharset = strCharset.substr(strCharset.find("=")+1);
                }
                if(!strCharset.empty()) {
                    if((nArkWebRetCode = WebResponse_SetCharset(strCharset)) != ARKWEB_NET_OK) {
                        if(nArkWebRetCode) {
                            OH_LOG_ERROR(LOG_APP, "WebResponse_SetCharset(strCharset.c_str(){%{public}s})== %{public}d",strCharset.c_str(), nArkWebRetCode);
                        }
                        Response4XX(HttpCode::BAD_REQUEST);
                        return;
                    }
                }    
            }
            
            if(strcasecmp(iter->first.c_str(), "Set-Cookie") == 0) {
                vector<string> vecCordovaCookie;
                vecCordovaCookie.push_back(iter->second);
                SystemCookieManager::setCookie(strHttpUrl, vecCordovaCookie);
            }
        }
        
        //设置http的内容长度
        FILE* file = FileCache::openFile(strRequestFileName,strCachePath);
        if(file == NULL) {
            Response4XX(HttpCode::NOT_FOUND);
            return;
        }
        long fileSize = FileCache::getFileSize(file);
        char szBuf[256];
        sprintf(szBuf, "%ld", fileSize);
        if((nArkWebRetCode = WebResponse_SetHeaderByName("Content-Length", szBuf)) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", szBuf{%{public}s})== %{public}d",szBuf, nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        
        //设置返回的response的数据
        vector<SMemPage> vecMemPage;
        const int blockSize = ((CMemPool*)Application::g_memPool)->GetPageSize();
        long consumed = 0;
        long totalConsumed = fileSize;
        ((CMemPool*)Application::g_memPool)->MallocPage(vecMemPage, 1);
        if(vecMemPage.size() < 1) {
            OH_LOG_ERROR(LOG_APP, "((CMemPool*)Application::g_memPool)->MallocPage(vecMemPage, 1) == NULL");
            Response4XX(HttpCode::BAD_REQUEST);
            ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
            return;
        }
        
        //webview请求部分返回，
        if(mapHeader.find("Range") != mapHeader.end()) {
            //部分返回设定状态码为206
            if((nArkWebRetCode = WebResponse_SetStatus(HttpCode::PARTIAL_CONTENT)) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetStatus(HttpCode::PARTIAL_CONTENT{206}) == %{public}d", nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
                return;
            }
            
            //localhost访问的是本地文件，对文件进行拆分返回webview
            if(strDomain == "localhost") {
                consumed = lngRangeStart>fileSize?fileSize:lngRangeStart;
                if(lngRangeEnd == 0) {
                    lngRangeEnd = fileSize<blockSize?fileSize:blockSize;
                    lngRangeEnd += consumed;
                }
                if(lngRangeEnd >= fileSize) {
                    lngRangeEnd = fileSize;
                }
                totalConsumed = lngRangeEnd;
                
                sprintf(szBuf, "%ld", lngRangeEnd-consumed);
                OH_LOG_INFO(LOG_APP, "Content-Length:%{public}d",lngRangeEnd-consumed);
                if((nArkWebRetCode = WebResponse_SetHeaderByName("Content-Length", szBuf)) != ARKWEB_NET_OK) {
                    if(nArkWebRetCode) {
                        OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", szBuf{%{public}s})== %{public}d",szBuf, nArkWebRetCode);
                    }
                    Response4XX(HttpCode::BAD_REQUEST);
                    ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
                    return;
                }
                OH_LOG_INFO(LOG_APP, "Accept-Ranges:bytes",szBuf);
                if((nArkWebRetCode = WebResponse_SetHeaderByName("Accept-Ranges", "bytes")) != ARKWEB_NET_OK) {
                    if(nArkWebRetCode) {
                        OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", \"bytes\"})== %{public}d",nArkWebRetCode);
                    }
                    Response4XX(HttpCode::BAD_REQUEST);
                    ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
                    return;
                }
                sprintf(szBuf, "bytes %ld-%ld/%ld", lngRangeStart, lngRangeEnd-1, fileSize);
                OH_LOG_INFO(LOG_APP, "Content-Range:%{public}s",szBuf);
                if((nArkWebRetCode = WebResponse_SetHeaderByName("Content-Range", szBuf)) != ARKWEB_NET_OK) {
                    if(nArkWebRetCode) {
                        OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", szBuf{%{public}s})== %{public}d",szBuf, nArkWebRetCode);
                    }
                    Response4XX(HttpCode::BAD_REQUEST);
                    ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
                    return;
                }
            }
        }
        DidReceiveResponse();//返回的http头设置完毕
        
        unsigned  char* buffer = (unsigned  char*)vecMemPage[0].m_point;
        while (true) {
            int ret = FileCache::readFile(file, buffer, blockSize, consumed);
            OH_LOG_INFO(LOG_APP, "read cacheFile %{public}d bytes.", ret);
            if (ret == 0) {
                break;
            }
            if(consumed+ret>totalConsumed) {
                //读取内容大于了要求返回的内容，只返回部分内容
                ret = totalConsumed-consumed;
            }
            consumed += ret;
            DidReceiveData(buffer, ret);
            memset(buffer, 0, blockSize);
            if(consumed >= totalConsumed) {
                break;
            }
        }
        ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
        FileCache::closeFile(file);
        DidFinish();
        return;
    }
    //处理第10步结束（发送请求获取静态资源数）
    
    //11 发送请求获取动态资源数据
    //if(m_rawfilePath.empty() && (resourceType == STYLE_SHEET ||  resourceType == SCRIPT || resourceType == XHR || resourceType == MEDIA)) {
    if(m_rawfilePath.empty() && (resourceType == XHR || resourceType == MEDIA)) {
        string strRequest;
        strRequest = strMethod + " " + requestAddress + " HTTP/1.1\r\n";//%s %s HTTP/1.1\r\n
        
        //从内存池中取1页，设置http头
        vector<SMemPage> vecMemBuf;
        ((CMemPool*)Application::g_memPool)->MallocPage(vecMemBuf, 1);
        if(vecMemBuf.size() < 1) {
            OH_LOG_ERROR(LOG_APP, "((CMemPool*)Application::g_memPool)->MallocPage(vecMemBuf, 1) == NULL");
            return;
        }
        
        char* szBuf = vecMemBuf[0].m_point;
        if(nPort == 80 || nPort == 443)
            sprintf(szBuf, "Host:%s\r\n", strDomain.c_str());
        else
            sprintf(szBuf, "Host:%s:%d\r\n", strDomain.c_str(), nPort);
        strRequest += szBuf;
        
        //设置http头，剔除相关跨域头
        //剔除Sec-Fetch-*头，如果您的服务器部署了基于Fetch Metadata的安全策略，请求会被拒绝，后续版本迭代中会像浏览器一样增加Sec-Fetch-*头
        string strCookie;
        for(map<string,string>::iterator iter = mapHeader.begin(); iter != mapHeader.end(); ++iter){
            if(iter->first == "Origin" || iter->first == "Sec-Fetch-Dest" || iter->first == "Sec-Fetch-Mode" || iter->first == "Sec-Fetch-Site"|| iter->first == "If-Modified-Since"|| iter->first == "If-None-Match") {
                continue;
            }
            if(strcasecmp(iter->first.c_str(), "cookie") == 0) {
                strCookie = iter->second;
                continue;
            }
            
            sprintf(szBuf, "%s:%s\r\n", iter->first.c_str(),iter->second.c_str());
            strRequest += szBuf;
        }
        
        strCookie = SystemCookieManager::getCookie(strHttpUrl, strCookie);
        if(!strCookie.empty()) {
            strRequest += "Cookie:";
            strRequest += strCookie;
            strRequest += "\r\n";
        }
        
        sprintf(szBuf, "Connection:Keep-Alive\r\n");
        strRequest += szBuf;
        
        sprintf(szBuf, "Keep-Alive:timeout=5, max=1000\r\n");
        strRequest += szBuf;
        
        sprintf(szBuf, "Content-Length:%lu\r\n\r\n", m_vecRequestHttpBody.size());
        strRequest += szBuf;
        ((CMemPool*)Application::g_memPool)->FreePage(vecMemBuf);
        
        //设置http的body数据
        strRequest.insert(strRequest.length(), (const char*)&m_vecRequestHttpBody[0], m_vecRequestHttpBody.size());
        
        //检查webview是否有代理，如果代理，发往代理服务器
        if(isHttpProxy) {
            strDomain = httpProxy.host;
            nPort = httpProxy.port;
        }
        ConnPoolManage* connPoolManage = (ConnPoolManage*)Application::g_connPoolManage;
        ConnPool* pool = connPoolManage->getConnPool(strDomain);
        if(pool == NULL) {
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        
        //开始发往web服务器处理请求
        vector<SMemPage> vecMemPage;
        if(isHttps) {
            bool isClose = false;
            SSL* ssl = NULL;
            if(!pool->getSSL(&ssl, nPort)) {
                OH_LOG_ERROR(LOG_APP, "pool->getSocket(&ssl) == false");
            }else if(!pool->sendWithTimeOut(ssl, strRequest, std::ref(m_stopped))) {
                OH_LOG_ERROR(LOG_APP, "pool->sendWithTimeOut(ssl, strRequest) == false");
            }else if(!pool->recvHttpWithTimeOut(ssl, vecMemPage, pMaxBuffer, nBufSize,isClose, std::ref(m_stopped))) {
                ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
            }
            pool->freeSocket(ssl, true);
        } else {
            bool isClose = false;
            int nSocket = -1;
            if(!pool->getSocket(nSocket, nPort)) {
                OH_LOG_ERROR(LOG_APP, "pool->getSocket(&nSocket) == false");
            }else if(!pool->sendWithTimeOut(nSocket, strRequest, std::ref(m_stopped))) {
                OH_LOG_ERROR(LOG_APP, "pool->sendWithTimeOut(nSocket, strRequest) == false");
            }else if(!pool->recvHttpWithTimeOut(nSocket, vecMemPage, pMaxBuffer, nBufSize,isClose, std::ref(m_stopped))) {
                ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
            }
            pool->freeSocket(nSocket, true);
        }
        
        if(m_stopped) {
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        
        if(vecMemPage.empty()) {
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        
        //获取response的状态码
        int httpCode = pool->getHttpCode(vecMemPage[0].m_point, vecMemPage[0].m_nCount);
        if(httpCode == 0) {
            ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        
        //获取response的http头
        map<string, string> mapRespHeaders;
        if(!pool->getHttpHeaders(vecMemPage[0].m_point, vecMemPage[0].m_nCount,mapRespHeaders)) {
            ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        
        //获取返回的Set-Cookie头，并设置cookie
        vector<string> vecCordovaCookie;
        pool->getCookies(vecMemPage[0].m_point, vecMemPage[0].m_nCount, vecCordovaCookie);
        SystemCookieManager::setCookie(strHttpUrl, vecCordovaCookie);
        
       
        /*
        *计算实际接收的数据长度
        *Content-Length=nAllCount(数据总长度)-nHeaderPos(http头结束位置)
        *Transfer-Encoding：必须经过内部数据处理后返回给webview，webview不会自行处理
        *   分段接收：Transfer-Encoding:chunked，内部已经处理，删除了分段标记(长度\r\n),返回到前端已经是实际长度
        *   数据压缩：Transfer-Encoding:gzip，内部已解压，返回给webview是实际解压后的数据
        *   Transfer-Encoding:compress 不支持
        *   Transfer-Encoding:deflate 不支持
        *Content-Encoding：无论数据是什么格式，原数据返回给webview，有webview处理
        *httpCode：206:原数据返回给webview
        */
        int nHeaderPos = pool->getHttpHeader(vecMemPage[0].m_point, vecMemPage[0].m_nCount);
        int nAllCount = ((CMemPool*)Application::g_memPool)->GetMemPageUseLength(vecMemPage);
        char szContentLength[64];
        sprintf(szContentLength, "%d", nAllCount-nHeaderPos);
        if((nArkWebRetCode = WebResponse_SetStatus(httpCode)) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetStatus(httpCode{%{public}d}) == %{public}d", httpCode, nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        if((nArkWebRetCode = WebResponse_SetCharset("UTF-8")) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetCharset(\"UTF-8\")== %{public}d", nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        if((nArkWebRetCode = WebResponse_SetHeaderByName("Content-Length", szContentLength)) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", szBuf{%{public}d})== %{public}d", szContentLength, nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        
        if(isAllowCredentials) {
            if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Origin", strOrigin)) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "OH_ArkWebResponse_SetHeaderByName(\"Access-Control-Allow-Origin\", \"%{public}s\")== %{public}d", strOrigin.c_str(), nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }   
            if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Methods\", \"POST, GET, OPTIONS\") == %{public}d", nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
            if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Headers", strCustomHttpHeaders)) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Headers\", \"%{public}s\") == %{public}d",strCustomHttpHeaders.c_str(), nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
            if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Credentials", "true")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Credentials\", \"true\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
        } else {
            if((nArkWebRetCode = WebResponse_SetHeaderByName( "Access-Control-Allow-Origin", "*")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Origin\", \"*\") == %{public}d", nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Methods", "*")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "OH_ArkWebResponse_SetHeaderByName(\"Access-Control-Allow-Methods\", \"*\") == %{public}d", nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Headers", "*")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Headers\", \"*\") == %{public}d", nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            } else if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Allow-Credentials", "false")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Allow-Credentials\", \"false\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
        }
        
        //过滤跨域标记、Transfer-Encoding和Content-Length
        string isAcceptRanges = pool->getAcceptRanges(vecMemPage[0].m_point, vecMemPage[0].m_nCount);
        for(map<string,string>::iterator iter = mapRespHeaders.begin(); iter != mapRespHeaders.end(); ++iter){
            if(strcasecmp(iter->first.c_str(), "Access-Control-Allow-Origin") != 0 
                && strcasecmp(iter->first.c_str(), "Access-Control-Allow-Methods") != 0 
                && strcasecmp(iter->first.c_str(), "Access-Control-Allow-Headers") != 0 
                && strcasecmp(iter->first.c_str(), "Access-Control-Allow-Credentials") != 0 
                && strcasecmp(iter->first.c_str(), "Transfer-Encoding") != 0 
                && strcasecmp(iter->first.c_str(), "Content-Length") != 0) {
                if((nArkWebRetCode = WebResponse_SetHeaderByName(iter->first, iter->second)) != ARKWEB_NET_OK) {
                    if(nArkWebRetCode) {
                        OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(iter->first.c_str(){%{public}s}, iter->second.c_str(){%{public}s}) == %{public}d", iter->first.c_str(), iter->second.c_str(), nArkWebRetCode);
                    }
                    Response4XX(HttpCode::BAD_REQUEST);
                    return;
                }
            }
            
            //收到206部分返回，重新设定Content-Length使用响应头返回的数据长度
            if(strcasecmp(iter->first.c_str(), "Content-Length") == 0 && isAcceptRanges == "bytes" && httpCode == HttpCode::PARTIAL_CONTENT) {
                if((nArkWebRetCode = WebResponse_SetHeaderByName(iter->first, iter->second)) != ARKWEB_NET_OK) {
                    if(nArkWebRetCode) {
                        OH_LOG_ERROR(LOG_APP, "OH_ArkWebResponse_SetHeaderByName(iter->first.c_str(){%{public}s}, iter->second.c_str(){%{public}s}) == %{public}d", iter->first.c_str(), iter->second.c_str(), nArkWebRetCode);
                    }
                    Response4XX(HttpCode::BAD_REQUEST);
                    return;
                }
            }
        }
        
        //Access-Control-Expose-Headers:跨域请求，允许暴露个给js的http头，如果服务器没有设置，cordova默认将所有头都暴露，否则按照服务器的设置返回
        if(mapRespHeaders.find("Access-Control-Expose-Headers") == mapRespHeaders.end() && mapRespHeaders.find("access-control-expose-headers") == mapRespHeaders.end()) {
            if((nArkWebRetCode = WebResponse_SetHeaderByName("Access-Control-Expose-Headers", "*")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Access-Control-Expose-Headers\", \"*\") == %{public}d",  nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                return;
            }
        }
        
        //响应头设置完毕，打印返回响应数据内存，最大打印2048个字符
        char szBufTmp[2048];
        memset(szBufTmp, 0, sizeof(szBufTmp));
        memcpy(szBufTmp, vecMemPage[0].m_point, nHeaderPos>2048||nHeaderPos>vecMemPage[0].m_nCount?2048:nHeaderPos);
        szBufTmp[2047] = 0;
        OH_LOG_INFO(LOG_APP, "response:%{public}s", szBufTmp);
        DidReceiveResponse();
        
        
        //设置返回的数据内容
        int nBodyPos = pool->getHttpHeader(vecMemPage[0].m_point, vecMemPage[0].m_nCount);
        for(int i=0; i<vecMemPage.size(); i++) {
            char* pResData = NULL;
            int nResLength = 0;
            if(i == 0)  {
                pResData = vecMemPage[i].m_point + nBodyPos;
                nResLength = vecMemPage[i].m_nCount - nBodyPos;
            } else {
                pResData = vecMemPage[i].m_point;
                nResLength = vecMemPage[i].m_nCount;
            }
           DidReceiveData((unsigned  char*)pResData, nResLength);     
        }
        ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
        DidFinish();
        return;
    }
    //处理第11步结束（发送请求获取动态资源数据）
    
    /*
    *12:根据虚拟域名加载本地沙箱文件或者从rawfile加载文件
    *   第10步是从本地沙箱路径或者web服务器端加载静态资源文件
    *   第11步是从web服务器，动态处理请求
    *   虽然第12步也是有加载本地沙箱文件，第10步也有加载本地沙箱文件，区别在于第12步是通过虚拟域名加载的，第10步是localhost域名或者cdvfile加载
    */
    if(m_rawfilePath.empty()) {
        Response4XX(HttpCode::FORBIDDEN);
        return;
    }
    
    if (!m_resourceManager) {
        OH_LOG_ERROR(LOG_APP, "read rawfile error, resource manager is nullptr.");
        Response4XX(HttpCode::FORBIDDEN);
        return;
    }
    
    string strMimeType = HttpUrl::GetMimeType(m_rawfilePath);
    if((nArkWebRetCode = WebResponse_SetMimeType(strMimeType)) != ARKWEB_NET_OK) {
        if(nArkWebRetCode) {
            OH_LOG_ERROR(LOG_APP, "WebResponse_SetMimeType(strMimeType{%{public}s}) == %{public}d",  strMimeType.c_str(), nArkWebRetCode);
        }
        Response4XX(HttpCode::BAD_REQUEST);
        return;
    }
    
    if((nArkWebRetCode = WebResponse_SetCharset("UTF-8")) != ARKWEB_NET_OK) {
         if(nArkWebRetCode) {
            OH_LOG_ERROR(LOG_APP, "WebResponse_SetCharset(\"UTF-8\") == %{public}d",  nArkWebRetCode);
        }
        Response4XX(HttpCode::BAD_REQUEST);
        return;
    }
    
    /*
    *rawfile资源目录是只读的，所有自定义webview或者热更新推送的代码，存在热更新目录下，热更新目录有插件设定
    *说明：从rawfile加载资源时，如果热更新目录下有目录结构和名字相对一致的，优先从热更新目录下加载
    */
    string strFilePath = Application::g_strHotCodeUpdateDirectory;
    if(!m_rawfilePath.empty() && !strFilePath.empty() && FileCache::IsFile("/"+m_rawfilePath, strFilePath)) {
        if((nArkWebRetCode = WebResponse_SetStatus(HttpCode::OK)) != ARKWEB_NET_OK) {
             if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetStatus(200) == %{public}d",  nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        if((nArkWebRetCode = WebResponse_SetCharset("UTF-8")) != ARKWEB_NET_OK) {
             if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetCharset(\"UTF-8\") == %{public}d",  nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        long len = FileCache::getFileSize(strFilePath+m_rawfilePath);
        if((nArkWebRetCode = WebResponse_SetHeaderByName("content-length", std::to_string(len))) != ARKWEB_NET_OK) {
             if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"content-length\", std::to_string(len).c_str(){%{public}d}, false) == %{public}d", std::to_string(len).c_str(), nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        DidReceiveResponse();
        
        FILE* file = FileCache::openFile("/"+m_rawfilePath, strFilePath);
        if(file == NULL) {
            OH_LOG_ERROR(LOG_APP, "FileCache::openFile(m_rawfilePath{%{public}s}, strFilePath{%{public}s}) == NULL",m_rawfilePath.c_str(), strFilePath.c_str());
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        vector<SMemPage> vecMemPage;
        const int blockSize = ((CMemPool*)Application::g_memPool)->GetPageSize();
        long consumed = 0;
        ((CMemPool*)Application::g_memPool)->MallocPage(vecMemPage, 1);
        if(vecMemPage.size() < 1) {
            OH_LOG_ERROR(LOG_APP, "((CMemPool*)Application::g_memPool)->MallocPage(vecMemPage, 1) == NULL");
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        unsigned  char* buffer = (unsigned  char*)vecMemPage[0].m_point;
        while (true) {
            int ret = FileCache::readFile(file, buffer, blockSize, consumed);
            OH_LOG_INFO(LOG_APP, "read cacheFile %{public}d bytes. file:%{public}s", ret, m_rawfilePath.c_str());
            if (ret == 0) {
                break;
            }
            consumed += ret;
            DidReceiveData(buffer, ret);
            memset(buffer, 0, blockSize);
        }
        FileCache::closeFile(file);
        ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
        DidFinish();
        return;
    }
    
    /*从沙箱目录下加载文件
    *路径:https://www.example.com/data/storage/el2/base/file/index.html在当前步骤处理（第14步），现实开发中，此中情况比较少用
    *路径:cdvfile://data/storage/el2/base/file/index.html在第10步已处理
    *路径:https://localhost/data/storage/el2/base/file/index.html在第10步已处理
    *m_rawfilePath：文件路径包含文件名，前面并没有"/"，从本地沙箱路径需加上"/"
    */
    string strBaseDir = Application::g_databaseDir.substr(1, Application::g_databaseDir.find("el2/database")-1);
    if(m_rawfilePath.find(strBaseDir) != string::npos) {
        strFilePath = "/";
        if(!FileCache::IsFile(m_rawfilePath, strFilePath)) {
             Response4XX(HttpCode::NOT_FOUND);
             return;
        }
        
        if((nArkWebRetCode = WebResponse_SetStatus(HttpCode::OK)) != ARKWEB_NET_OK) {
             if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetStatus(200) == %{public}d",  nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        long fileSize = FileCache::getFileSize(strFilePath+m_rawfilePath);
        if((nArkWebRetCode = WebResponse_SetHeaderByName("content-length", std::to_string(fileSize).c_str())) != ARKWEB_NET_OK) {
             if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"content-length\", std::to_string(len).c_str(){%{public}d}, false) == %{public}d", std::to_string(fileSize).c_str(), nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        vector<SMemPage> vecMemPage;
        const int blockSize = ((CMemPool*)Application::g_memPool)->GetPageSize();
        long consumed = 0;
        long totalConsumed = fileSize;
        ((CMemPool*)Application::g_memPool)->MallocPage(vecMemPage, 1);
        if(vecMemPage.size() < 1) {
            OH_LOG_ERROR(LOG_APP, "((CMemPool*)Application::g_memPool)->MallocPage(vecMemPage, 1) == NULL");
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
        
        if(mapHeader.find("Range") != mapHeader.end()) {
            //部分返回设定状态码为206
            if((nArkWebRetCode = WebResponse_SetStatus(HttpCode::PARTIAL_CONTENT)) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetStatus(HttpCode::PARTIAL_CONTENT{206}) == %{public}d", nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
                return;
            }
            
            consumed = lngRangeStart>fileSize?fileSize:lngRangeStart;
            if(lngRangeEnd == 0) {
                lngRangeEnd = fileSize<blockSize?fileSize:blockSize;
                lngRangeEnd += consumed;
            }
            if(lngRangeEnd >= fileSize) {
                lngRangeEnd = fileSize;
            }
            totalConsumed = lngRangeEnd;
            char szBuf[256];    
            sprintf(szBuf, "%ld", lngRangeEnd-consumed);
            OH_LOG_INFO(LOG_APP, "Content-Length:%{public}d",lngRangeEnd-consumed);
            if((nArkWebRetCode = WebResponse_SetHeaderByName("Content-Length", szBuf)) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", szBuf{%{public}s})== %{public}d",szBuf, nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
                return;
            }
            OH_LOG_INFO(LOG_APP, "Accept-Ranges:bytes",szBuf);
            if((nArkWebRetCode = WebResponse_SetHeaderByName("Accept-Ranges", "bytes")) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", \"bytes\"})== %{public}d",nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
                return;
            }
            sprintf(szBuf, "bytes %ld-%ld/%ld", lngRangeStart, lngRangeEnd-1, fileSize);
            OH_LOG_INFO(LOG_APP, "Content-Range:%{public}s",szBuf);
            if((nArkWebRetCode = WebResponse_SetHeaderByName("Content-Range", szBuf)) != ARKWEB_NET_OK) {
                if(nArkWebRetCode) {
                    OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", szBuf{%{public}s})== %{public}d",szBuf, nArkWebRetCode);
                }
                Response4XX(HttpCode::BAD_REQUEST);
                ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
                return;
            }
        }
        DidReceiveResponse();
        
        FILE* file = FileCache::openFile(strFilePath+m_rawfilePath, "");
        if(file == NULL) {
            OH_LOG_ERROR(LOG_APP, "FileCache::openFile(m_rawfilePath{%{public}s}, strFilePath{%{public}s}) == NULL",m_rawfilePath.c_str(), strFilePath.c_str());
            Response4XX(HttpCode::NOT_FOUND);
            return;
        }
        
        unsigned  char* buffer = (unsigned  char*)vecMemPage[0].m_point;
        while (true) {
            int ret = FileCache::readFile(file, buffer, blockSize, consumed);
            OH_LOG_INFO(LOG_APP, "read cacheFile %{public}d bytes. file:%{public}s", ret, m_rawfilePath.c_str());
            if (ret == 0) {
                break;
            }
            if(consumed+ret>totalConsumed) {
                //读取内容大于了要求返回的内容，只返回部分内容
                ret = totalConsumed-consumed;
            }
            consumed += ret;
            DidReceiveData(buffer, ret);
            memset(buffer, 0, blockSize);
            if(consumed >= totalConsumed) {
                break;
            }
        }
        FileCache::closeFile(file);
        ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
        DidFinish();
        return;
    }
    
    //从rawfile加载资源文件
    RawFile *rawfile = OH_ResourceManager_OpenRawFile(m_resourceManager, m_rawfilePath.c_str());
    if (!rawfile) {
        Response4XX(HttpCode::NOT_FOUND);
        return;
    } else {
        if((nArkWebRetCode = WebResponse_SetStatus(HttpCode::OK)) != ARKWEB_NET_OK) {
             if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetStatus(HttpCode::OK{200}) == %{public}d",  nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            return;
        }
    }
    
    long fileSize = OH_ResourceManager_GetRawFileSize(rawfile);
    if((nArkWebRetCode = WebResponse_SetHeaderByName("content-length", std::to_string(fileSize).c_str())) != ARKWEB_NET_OK) {
         if(nArkWebRetCode != 0) {
            OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"content-length\", std::to_string(len).c_str(){%{public}d}) == %{public}d", std::to_string(fileSize).c_str(), nArkWebRetCode);
        }
        Response4XX(HttpCode::BAD_REQUEST);
        return;
    }
    vector<SMemPage> vecMemPage;
    const int blockSize = ((CMemPool*)Application::g_memPool)->GetPageSize();
    long consumed = 0;
    long totalConsumed = fileSize;
    ((CMemPool*)Application::g_memPool)->MallocPage(vecMemPage, 1);
    if(vecMemPage.size() < 1) {
        OH_LOG_ERROR(LOG_APP, "((CMemPool*)Application::g_memPool)->MallocPage(vecMemPage, 1) == NULL");
        Response4XX(HttpCode::BAD_REQUEST);
        return;
    }
    //数据只需部分返回
    if(mapHeader.find("Range") != mapHeader.end()) {
        //部分返回设定状态码为206
        if((nArkWebRetCode = WebResponse_SetStatus(HttpCode::PARTIAL_CONTENT)) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetStatus(HttpCode::PARTIAL_CONTENT{206}) == %{public}d", nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
            return;
        }
        
        consumed = lngRangeStart>fileSize?fileSize:lngRangeStart;
        if(lngRangeEnd == 0) {
            lngRangeEnd = fileSize<blockSize?fileSize:blockSize;
            lngRangeEnd += consumed;
        }
        if(lngRangeEnd >= fileSize) {
            lngRangeEnd = fileSize;
        }
        totalConsumed = lngRangeEnd;
        char szBuf[256];    
        sprintf(szBuf, "%ld", lngRangeEnd-consumed);
        OH_LOG_INFO(LOG_APP, "Content-Length:%{public}d",lngRangeEnd-consumed);
        if((nArkWebRetCode = WebResponse_SetHeaderByName("Content-Length", szBuf)) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", szBuf{%{public}s})== %{public}d",szBuf, nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
            return;
        }
        OH_LOG_INFO(LOG_APP, "Accept-Ranges:bytes",szBuf);
        if((nArkWebRetCode = WebResponse_SetHeaderByName("Accept-Ranges", "bytes")) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", \"bytes\"})== %{public}d",nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
            return;
        }
        sprintf(szBuf, "bytes %ld-%ld/%ld", lngRangeStart, lngRangeEnd-1, fileSize);
        OH_LOG_INFO(LOG_APP, "Content-Range:%{public}s",szBuf);
        if((nArkWebRetCode = WebResponse_SetHeaderByName("Content-Range", szBuf)) != ARKWEB_NET_OK) {
            if(nArkWebRetCode) {
                OH_LOG_ERROR(LOG_APP, "WebResponse_SetHeaderByName(\"Content-Length\", szBuf{%{public}s})== %{public}d",szBuf, nArkWebRetCode);
            }
            Response4XX(HttpCode::BAD_REQUEST);
            ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
            return;
        }
    }
    DidReceiveResponse();
    
    unsigned  char* buffer = (unsigned  char*)vecMemPage[0].m_point;
    while (true) {
        OH_ResourceManager_SeekRawFile(rawfile, consumed, 0);
        int ret = OH_ResourceManager_ReadRawFile(rawfile, buffer, blockSize);
        OH_LOG_INFO(LOG_APP, "read rawfile %{public}d bytes. file:%{public}s", ret, m_rawfilePath.c_str());
        if (ret == 0) {
            break;
        }
        if(consumed+ret>totalConsumed) {
            //读取内容大于了要求返回的内容，只返回部分内容
            ret = totalConsumed-consumed;
        }
        consumed += ret;
        DidReceiveData(buffer, ret);
        memset(buffer, 0, blockSize);
        if(consumed >= totalConsumed) {
            break;
        }
    }
    ((CMemPool*)Application::g_memPool)->FreePage(vecMemPage);
    OH_ResourceManager_CloseRawFile(rawfile);
    DidFinish();
    return;
}

//用户取消访问和访问结束后DidFinish会调用stop函数
void RawfileRequest::Stop()
{
    OH_LOG_INFO(LOG_APP, "stop the rawfile request. m_response(%{public}p)", m_response);
    std::lock_guard<std::mutex> guard(m_mutex);
    m_stopped = true;
    if (m_response) {
        OH_ArkWeb_DestroyResponse(m_response);
        m_response = nullptr;
    }
    
    if(m_stream) {
        OH_ArkWebResourceRequest_DestroyHttpBodyStream(m_stream);
        m_stream = nullptr;
    }
    
    OH_ArkWebResourceRequest_Destroy(m_resourceRequest);
    OH_ArkWebResourceHandler_Destroy(m_resourceHandler);
    m_resourceRequest = nullptr;
    m_resourceHandler = nullptr;
}

bool RawfileRequest::WebResourceRequest_GetUrl(char** url)
{
    std::lock_guard<std::mutex> guard(m_mutex);
    if(!m_stopped && Application::isValidSchemeHandler(m_schemeHandler)) {
        OH_ArkWebResourceRequest_GetUrl(m_resourceRequest, url);
        return true;
    }
    return false;
}
bool RawfileRequest::WebResourceRequest_GetMethod(char** method)
{
    std::lock_guard<std::mutex> guard(m_mutex);
    if(!m_stopped && Application::isValidSchemeHandler(m_schemeHandler)) {
        OH_ArkWebResourceRequest_GetMethod(m_resourceRequest, method);
        return true;
    }
    return false;
}

bool RawfileRequest::WebResourceRequest_GetResourceType(int& resourceType)
{
    std::lock_guard<std::mutex> guard(m_mutex);
    if(!m_stopped && Application::isValidSchemeHandler(m_schemeHandler)) {
        resourceType = OH_ArkWebResourceRequest_GetResourceType(m_resourceRequest);
        return true;
    }
    return false;
}
bool RawfileRequest::WebResourceRequest_GetRequestHeaders(ArkWeb_RequestHeaderList** headerList)
{
    std::lock_guard<std::mutex> guard(m_mutex);
    if(!m_stopped && Application::isValidSchemeHandler(m_schemeHandler)) {
        OH_ArkWebResourceRequest_GetRequestHeaders(m_resourceRequest, headerList);
        return true;
    }
    return false;
}
int RawfileRequest::WebResponse_SetHeaderByName(const string& strName, const string& strValue)
{
    std::lock_guard<std::mutex> guard(m_mutex);
    if(!m_stopped) {
        return OH_ArkWebResponse_SetHeaderByName(m_response, strName.c_str(), strValue.c_str(), true);
    }
    return -1;
}
int  RawfileRequest::WebResponse_SetStatusText(const string& strText)
{
    std::lock_guard<std::mutex> guard(m_mutex);
    if(!m_stopped) {
        return OH_ArkWebResponse_SetStatusText(m_response, strText.c_str());
    }
    return -1;
}
int RawfileRequest::WebResponse_SetStatus(const int nStatus)
{
    std::lock_guard<std::mutex> guard(m_mutex);
    if(!m_stopped) {
        return OH_ArkWebResponse_SetStatus(m_response, nStatus);
    }
    return -1;
}
int RawfileRequest::WebResponse_SetMimeType(const string& strText)
{
    std::lock_guard<std::mutex> guard(m_mutex);
    if(!m_stopped) {
        return OH_ArkWebResponse_SetMimeType(m_response, strText.c_str());
    }
    return -1;
}
int RawfileRequest::WebResponse_SetCharset(const string& strCharset)
{
    std::lock_guard<std::mutex> guard(m_mutex);
    if(!m_stopped) {
        return OH_ArkWebResponse_SetCharset(m_response, strCharset.c_str());
    }
    return -1;
}
void RawfileRequest::DidReceiveResponse()
{
    OH_LOG_INFO(LOG_APP, "did receive response.");
    std::lock_guard<std::mutex> guard(m_mutex);
    if (!m_stopped && Application::isValidSchemeHandler(m_schemeHandler)) {
        OH_ArkWebResourceHandler_DidReceiveResponse(m_resourceHandler, m_response);
    }
}

void RawfileRequest::DidReceiveData(const uint8_t *buffer, int64_t bufLen)
{
    OH_LOG_INFO(LOG_APP, "did receive data.");
    std::lock_guard<std::mutex> guard(m_mutex);
    if (!m_stopped && Application::isValidSchemeHandler(m_schemeHandler)) {
        OH_ArkWebResourceHandler_DidReceiveData(m_resourceHandler, buffer, bufLen);
    }
}

void RawfileRequest::DidFinish()
{
    OH_LOG_INFO(LOG_APP, "did finish.");
    std::lock_guard<std::mutex> guard(m_mutex);
    if (!m_stopped && Application::isValidSchemeHandler(m_schemeHandler)) {
        OH_ArkWebResourceHandler_DidFinish(m_resourceHandler);
    }
    m_finished = true;
}

void RawfileRequest::DidFailWithError(ArkWeb_NetError errorCode)
{
    OH_LOG_INFO(LOG_APP, "did finish with error %{public}d.", errorCode);
    if (!m_stopped && Application::isValidSchemeHandler(m_schemeHandler)) {
        OH_ArkWebResourceHandler_DidFailWithError(m_resourceHandler, errorCode);
    }
}

void RawfileRequest::Response4XX(const int nHttpCode)
{
    if(m_response != NULL && m_resourceRequest != nullptr && Application::isValidSchemeHandler(m_schemeHandler)) { //用户提前取消访问response会destroy掉，不能返回404
        WebResponse_SetStatus(nHttpCode);
        WebResponse_SetHeaderByName("Access-Control-Allow-Origin", "*");    
        WebResponse_SetHeaderByName("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
        WebResponse_SetHeaderByName("Access-Control-Allow-Headers", "X-PINGOTHER, Content-Type");
        WebResponse_SetHeaderByName("Content-Length", "0");
        DidReceiveResponse();
    } else {
        DidFailWithError(ARKWEB_ERR_CONNECTION_FAILED); //报错处理后，不会触发webview的onPageEnd函数，因此建议报404错误
    }
    DidFinish();
}

bool RawfileRequest::IsAllowUrl(const std::string & strUrl) 
{
    if(strUrl.find("//") == string::npos) {
        return false;
    }
    
    string strPath = strUrl.substr(strUrl.find("//")+2);
    if(strPath.find(Application::g_strTmpUrl) == 0)
        return true;
    
    if(!((CordovaViewController*)Application::g_cordovaViewController)->getPluginManager()->shouldAllowRequest(strUrl)) {
        OH_LOG_ERROR(LOG_APP, "unsupported domain:%{public}s", strUrl.c_str());
        return false;
    }
    return true;
}

/*
*用于判断是否可以销毁对象
*只有stop和finish都为true是，才可以destroy实例对象
*/
bool RawfileRequest::isTaskFinished()
{
     return (m_stopped && m_finished);
}

//从池中取出一页内存，供执行线程使用，避免申请内存，
void* CHttpGroupRunner::HttpRunner::InitThreadData() 
{ 
    vector<SMemPage> vecMemBuf;
    ((CMemPool*)Application::g_memPool)->MallocPage(vecMemBuf, 1);
    if(vecMemBuf.size() < 1) {
        OH_LOG_ERROR(LOG_APP,  "((CMemPool*)Application::g_memPool)->MallocPage(vecMemBuf, 1) == NULL");
        return NULL;
    }
    m_nBufSize = ((CMemPool*)Application::g_memPool)->GetPageSize();
    return vecMemBuf[0].m_point;
}
//线程执行完毕，将内存页放回内存池中，避免内存泄漏，便于其他地方复用内存
void CHttpGroupRunner::HttpRunner::DeInitThreadData(void* pArg)
{
    ((CMemPool*)Application::g_memPool)->FreePage((char*)pArg);
}

void CHttpGroupRunner::InitGroup(const int nGroupCount, const int nThreadCount)
{
    for(int i=0; i<nGroupCount; i++) {
       HttpRunner* pHttp =  new HttpRunner();
       pHttp->SetPoolSize(nThreadCount);
       pHttp->Start(NULL);
       m_queGroupHttp.push(pHttp);
    }
}

bool CHttpGroupRunner::AddTask(const RawfileRequest* rawfileRequest)
{
    //添加任务之前，先处理组的调度，把没有任务的池返回组的池中
    std::lock_guard<std::mutex> guard(m_mutex);
    for(auto it = m_mapUrlToHttpRunner.begin(); it != m_mapUrlToHttpRunner.end(); ) {
        if(it->second->GetWaitingThreads() == it->second->GetCurPoolSize()) {
            m_queGroupHttp.push(it->second);
            it = m_mapUrlToHttpRunner.erase(it);
        } else {
            it++;
        }
    }
    
    string strKey = rawfileRequest->GetSchemeDomainPort();
    //url是否已经有正在处理的线程池，如果有直接往已有的池中添加任务
    if(m_mapUrlToHttpRunner.find(strKey) != m_mapUrlToHttpRunner.end()) {
        HttpRunner* pHttp = m_mapUrlToHttpRunner[strKey];
        pHttp->AddTask(rawfileRequest);
        OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "AddTask", "same domain number:%{public}d thread num:%{public}d", m_mapUrlToHttpRunner.size(), pHttp->GetCurPoolSize());
        return true;
    }
    
    //没有空闲的组了，需要创建一个新组的线程池
    if(m_queGroupHttp.empty() && m_mapUrlToHttpRunner.size() < MAX_URL_BOUNDARY_RUN_TIME) {
       HttpRunner* pHttp =  new HttpRunner();
       pHttp->SetPoolSize(2);
       pHttp->Start(NULL);
       m_queGroupHttp.push(pHttp); 
    }
    
    if(!m_queGroupHttp.empty()) {
        HttpRunner* pHttp = m_queGroupHttp.front();
        m_queGroupHttp.pop();
        m_mapUrlToHttpRunner[strKey] = pHttp;
        pHttp->AddTask(rawfileRequest);
        OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "AddTask", "new domain number:%{public}d thread num:%{public}d", m_mapUrlToHttpRunner.size(), pHttp->GetCurPoolSize());
        return true;
    }

    //请求任务添加失败，已经达到边界了，该边界是同时正在请求的域名数量为MAX_URL_BOUNDARY_RUN_TIME个
    return false;
}